﻿namespace MicroCloud.Entity
{
    /// <summary>
    /// 依赖注入服务集合扩展
    /// </summary>
    public static class ServiceExtensions
    {
        /// <summary>
        /// 获取或设置 迁移的程序集名称
        /// </summary>
        public static string MigrationAssemblyName { get; set; }

        /// <summary>
        /// 将基于MicroCloud数据上下文基类 <see cref="DbContextBase"/> 上下文类型添加到服务集合中
        /// </summary>
        /// <typeparam name="TDbContext">基于MicroCloud数据上下文基类 <see cref="DbContextBase"/> 上下文类型</typeparam>
        /// <param name="services">依赖注入服务集合</param>
        /// <param name="optionsAction">数据库选项创建配置，将在内置配置后运行</param>
        /// <returns>依赖注入服务集合</returns>
        public static IServiceCollection AddMicroCloudDbContext<TDbContext>(this IServiceCollection services, Action<IServiceProvider, DbContextOptionsBuilder> optionsAction = null) where TDbContext : DbContext
        {
            services = services.AddDbContext<TDbContext>((provider, builder) =>
            {
                builder = provider.BuildDbContextOptionsBuilder<TDbContext>(builder);
                //额外的选项
                optionsAction?.Invoke(provider, builder);
            });
            return services;
        }

        /// <summary>
        /// 构建 <see cref="DbContextOptionsBuilder"/> 附加必要的扩展属性
        /// </summary>
        /// <typeparam name="TDbContext">数据上下文类型</typeparam>
        /// <param name="provider">服务提供者</param>
        /// <param name="builder">数据上下文配置构建器</param>
        /// <returns></returns>
        public static DbContextOptionsBuilder BuildDbContextOptionsBuilder<TDbContext>(this IServiceProvider provider, DbContextOptionsBuilder builder)
            where TDbContext : DbContext
        {
            Type dbContextType = typeof(TDbContext);
            MicroCloudOptions options = provider.GetMicroCloudOptions();
            DbContextOption dbContextOptions = (options?.GetDbContextOptions(dbContextType)) ?? throw new Exception(I18N.T("无法找到数据上下文 {0} 的配置信息", dbContextType.DisplayName()));
            ILogger logger = provider.GetLogger(typeof(ServiceExtensions));

            //启用延迟加载
            if (dbContextOptions.LazyLoadingProxiesEnabled)
            {
                builder = builder.UseLazyLoadingProxies(true);   //开启延迟加载 默认是开启的 true
                //builder = builder.ConfigureWarnings(warnings => warnings.Ignore(CoreEventId.DetachedLazyLoadingWarning));    //忽略AsNoTracking 报错
                logger.LogDebug("数据上下文类型 {dbContextType} 应用延迟加载代理", dbContextType);
            }
            DatabaseType databaseType = dbContextOptions.DatabaseType;

            //处理数据库驱动差异处理
            IDbContextOptionsBuilderDriveHandler driveHandler = provider.GetServices<IDbContextOptionsBuilderDriveHandler>().FirstOrDefault(m => m.Type == databaseType) ?? throw new Exception(I18N.T("无法解析类型为 {0} 的 {1} 实例，是否未在Startup执行AddPack<{0}{1}MigrationPack>()", databaseType, typeof(IDbContextOptionsBuilderDriveHandler).DisplayName(), typeof(TDbContext).Name));

            //选择主/从数据库连接串
            IConnectionStringProvider connectionStringProvider = provider.GetRequiredService<IConnectionStringProvider>();
            string connectionString = connectionStringProvider.GetConnectionString(dbContextOptions);

            ScopedDictionary scopedDictionary = provider.GetRequiredService<ScopedDictionary>();
            string key = $"DbConnection_{connectionString}";
            DbConnection existingDbConnection = scopedDictionary.GetValue<DbConnection>(key);
            builder = driveHandler.Handle(builder, connectionString, existingDbConnection, dbContextOptions);

            //使用模型缓存
            DbContextModelCache modelCache = provider.GetService<DbContextModelCache>();
            IModel model = modelCache?.Get(dbContextType);
            if (model != null)
            {
                builder = builder.UseModel(model);
            }

            return builder;
        }

    }
}